iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 7
0
Mobile Development

Android Architecture Components 學習心得筆記系列 第 7

Day 7 ViewModel (Last) 應用與心得總結

  • 分享至 

  • xImage
  •  

MVVM

如果需要透過 constructor 來傳遞參數給 ViewModel 該怎麼做

ViewModel 在創建時,都是透過 ViewModelProviders 這個類來生成

viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)

那需要傳遞參數給 ViewModel 時就不能透過 constructor 來傳。

Solution:
創建一個 ViewModelFactory 輔助類,並繼承 NewInstanceFactory,這時候就可以把想要傳給ViewModel 的參數放在 constructor,例如:把 MainRepository 傳進來。

class ViewModelFactory constructor(private val repository: MainRepository) : ViewModelProvider.NewInstanceFactory() {
...
}

接著覆寫裡面的 create 方法,這裡去判斷 ViewModelProvider 接到的 ViewModel 是哪一個 class,
並返回相對應的 ViewModel,這裡返回的 ViewModel 就可以放進任何想要的參數了

override fun <T : ViewModel?> create(modelClass: Class<T>): T =
    with(modelClass) {

        when {
            isAssignableFrom(MainViewModel::class.java) -> MainViewModel(repository)
            else ->
                throw IllegalArgumentException(
                    "Unknown ViewModel class: ${modelClass.name}")
        }
    } as T

這裡如果有多個 ViewModel 共用 repository 的話,在 when 裡面增加判斷式就可以使用了。

其實 ViewModelProvider 裡面還有另一個 ViewModelProvider.Factory 可以用,和NewInstanceFactory 的差別在於,ViewModelProvider.Factory 每次都會重新創建一個新的 ViewModel, NewInstanceFactory 則是同一個實例,這個知道一下就好了,可能某些特殊情況才會用到 ViewModelProvider.Factory

將 Activity 創建 ViewModel 的代碼

viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)

修改成

val factory = ViewModelFactory(MainRepository())

viewModel = ViewModelProviders.of(this,factory).get(MainViewModel::class.java)

多丟一個 factory 參數進去而已,接著就可以把 constructor 改成想要的樣子了。

class MainViewModel(private val repository: MainRepository) : ViewModel() {

Fragment 之間共享數據

以往 Fragment 之間要傳遞數據,得依賴他們的 parent Activity 當作媒介來從 Fragment A 傳遞數據到 Fragment B,還得小心配置變更時可能把數據丟失的麻煩。

現在能夠透過使用 ViewModel 來達成 Fragment 之間共享數據,而且使用的方式非常簡單
只需要將需要共享數據的 Fragment 裡面的

viewModel = ViewModelProviders.of(this).get(FragmentViewModel::class.java)

改成

viewModel = activity?.run {
            ViewModelProviders.of(this).get(FragmentViewModel::class.java)
        } ?: throw Exception("Invalid Activity")

其實只是把丟給 ViewModelProviders 的實例從 Fragment 換成 Activity 而已

這時候 ViewModel 的生命週期就會依賴於 Acitvity,進而讓 Fragment 共同持有。

ViewModel 小結

剛開始對 ViewModel 的認知就是透過觀察者模式實現數據變動時 UI 層可以感知到變化,那時候想說,不就好像是丟一個 callback 給 ViewModel,成功要到數據再叫回來嗎?好像沒什麼特別的。

的確只看這部分的話, ViewModel 跟 callback 有超過 87% 的相似度,但是 ViewModel 還有更多的優點

  • 目前最新的架構,很潮
  • 省去配置變更(例如旋轉手機)後保存數據的麻煩
  • 實現 Fragment 之間的數據共享
  • 能夠搭配 DatabindingLiveData 實現響應式 UI

所謂 響應式 UI 就是數據變動時 UI 層不只可以感知到變化,而且會自動更新,非常的炫砲!

有任何問題或講得不清楚的地方歡迎留言和我討論。

更歡迎留言糾正我任何說錯的地方!

下一篇開始,來看看如何使用 Databinding 實現響應式 UI。

下一篇:Data Binding (一) 介紹與基本使用


上一篇
Day 6 ViewModel (一) 介紹與基本使用
下一篇
Day 8 Data Binding (一) 介紹與基本使用
系列文
Android Architecture Components 學習心得筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言